package com.sherlocky.document.web;

import com.alibaba.fastjson.JSON;
import com.sherlocky.document.constant.DocumentConstants;
import com.sherlocky.document.constant.DocumentStatus;
import com.sherlocky.document.entity.Document;
import com.sherlocky.document.entity.DocumentEditCallback;
import com.sherlocky.document.entity.DocumentEditCallbackResponse;
import com.sherlocky.document.entity.DocumentResponse;
import com.sherlocky.document.service.DocumentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author: zhangcx
 * @date: 2019/8/7 16:09
 */
@Slf4j
@RestController
@RequestMapping("/api")
@Api(tags = "文档相关接口")
public class DocumentApiController {
    @Autowired
    private DocumentService documentService;

    /**
     * ping --> pong
     * @return
     */
    @ApiOperation(value="测试", notes="正常返回：pong")
    @GetMapping("/ping")
    public String ping() {
        return "pong";
    }

    //TODO 写一个大的before？ 指定预览还是编辑？重复调用before编辑要更新redis缓存
    // viewer? editor?

    /**
     * 根据传入的文档路径预览文档,返回真正的预览地址："/view/{documentKey}"
     * @param path 文档实体文件路径（必需）
     * @param name 文档名称（非必需，默认为实体对应的文件名）
     */
    @ApiOperation(value="预览前置")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "path", value = "文档文件路径"),
            @ApiImplicitParam(name = "name", value = "文档标题")
    })
    @PostMapping("/before/view")
    public DocumentResponse beforeView(@RequestParam String path, @RequestParam(required = false) String name, HttpServletResponse response) throws IOException {
        /**
         * 为了保密，此处先返回一个无明确规则地址，再由该地址呈现预览
         */
        String documentKey = documentService.buildDocument(path, name);
        //Fixme 返回页面地址给调用方（是否添加过期时间？）
        Map<String, String> data = new HashMap<>();
        data.put("url", String.format(DocumentConstants.OFFICE_VIEWER, documentService.getServerHost(), documentKey));
        return DocumentResponse.success(data);
    }

    /**
     * @param path
     * @param name
     * @param response
     * @return
     * @throws IOException
     */
    @ApiOperation(value="编辑前置")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "path", value = "文档文件路径"),
            @ApiImplicitParam(name = "name", value = "文档标题")
    })
    @PostMapping("/before/edit")
    public DocumentResponse beforeEdit(@RequestParam String path, @RequestParam(required = false) String name, HttpServletResponse response) throws IOException {
        String documentKey = documentService.buildDocument(path, name);
        Map<String, String> data = new HashMap<>();
        // TODO 如果存在 before 方法，应该在此阻止pdf编辑请求
        data.put("url", String.format(DocumentConstants.OFFICE_EDITOR, documentService.getServerHost(), documentKey));
        return DocumentResponse.success(data);
    }

    /**
     * 获取文件实体（下载）
     * @param documentKey
     */
    /** 不生成swagger文档（onlyoffcie document server 调用） */
    @ApiIgnore
    @GetMapping("/file/{documentKey}")
    public void getDocFile(@PathVariable String documentKey, HttpServletRequest request, HttpServletResponse response) throws IOException {
        documentService.downloadDocumentFile(documentKey, request, response);
    }

    /**
     * 编辑后回调--保存文件实体
     * <p>onlyoffice在编辑后关闭文件的时候，会回调该接口</p>
     * @param callback
     */
    /** 不生成swagger文档（onlyoffcie document server 调用） */
    @ApiIgnore
    @PostMapping("/callback")
    public DocumentEditCallbackResponse saveDocumentFile(@RequestBody DocumentEditCallback callback) throws IOException {
        if (log.isInfoEnabled()) {
            log.info("### 编辑后回调, 回调信息：{}", callback);
        }
        // 需要保存时写出文件
        if (callback.getStatus() == DocumentStatus.READY_FOR_SAVING.getCode() || callback.getStatus() == DocumentStatus.BEING_EDITED_STATE_SAVED.getCode()) {
            if (log.isDebugEnabled()) {
                log.debug("@@@ 开始保存文件。。。");
            }
            boolean success = documentService.saveDocumentFile(callback.getKey(), callback.getUrl());
            if (log.isDebugEnabled()) {
                log.debug("@@@ 保存文件结束！");
            }
            if (!success) {
                return DocumentEditCallbackResponse.failue();
            }
        }
        return DocumentEditCallbackResponse.success();
    }

    @ApiOperation(value="获取文档信息")
    @ApiImplicitParam(name = "documentKey", value = "文档 key")
    @GetMapping("/doc/{documentKey}")
    public Document docData(@PathVariable String documentKey) {
        return documentService.getDocument(documentKey);
    }

    /**
     * 将某个对象转换成json格式并发送到客户端
     * @param response
     * @param obj
     * @throws Exception
     */
    private void sendJsonMessage(HttpServletResponse response, Object obj) throws IOException{
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print(JSON.toJSONString(obj));
        writer.close();
        response.flushBuffer();
    }
}
